need to drop MRN and patient_name, replacing with study_id, once this becomes a research project
Hypothesis 1: Discordance is a relatively common, yet under appreciated phenomenon, and varies by geographic location of care and patient attributes including demographics, severity of illness, and underlying disease process.
Hypothesis 2: Discordance between aPTT and anti-Xa indicates the presence of coagulation system pathophysiology which is a risk factor for development of hemorrhage and thrombosis.
Classic systemic anticoagulation goals, anti-Xa vs aPTT, at NYP:
Typical anti-Xa goal vs aPTT goals among heparinized ECMO patients:
0.1 - 0.3 vs 35 - 50 (LOW GOAL)
0.2 - 0.5 vs 45 - 65 (CLASSIC GOAL)
Only first ECMO run used.
ECMO duration: Dr. Connie Nguyen manually reviewed heparin-exposed patients’ EMRs in June 2025 to identify true ECMO time off, as initial data review identified some labs that were drawn while on heparin but after the patient was off ECMO. The variable “time_off” in the original data was obtained from ELSO sources. Per Dr. Nguyen’s review, if her evaluation of ECMO stop time was within 4 hours of ELSO-derived time_off, then the actual true time off was deemed as that known by ELSO. If there was a greater than 4 hour discrepancy, a new time_off_true value was recorded.
Lab cutoffs:
if aPTT <20.0 - made 0
if aPTT >180 - made 180
if anti-Xa <0.04 or <0.1 - made 0
if anti-Xa >2.00 - made 2.0
if data is duplicated at a specific timepoint (e.g. 2 lab samples, exact same result time but different values), then taking the mean of the two exact same-timed values
Hyperbilirubinemia can artifactually elevate anti-Xa (colorimetric assay). Jaundice threshold is 2 - 3 mg/dL total bilirubin. Upper limit of normal total bilirubin at NYP-CUIMC is 1.2 mg/dL.
need to redo all analyses, starting with run_labs_complications_raw, checking to ensure counts are correct, now that dataframe includes true ECMO stop times
| n |
|---|
| 166 |
| department_name | n |
|---|---|
| MIL 5 CTICU | 76 |
| MIL 5 CCU | 41 |
| MIL 4 MICU A | 31 |
| HRT CARDIAC CARE | 26 |
| MIL OPERATING ROOM | 5 |
| MIL 4 SICU | 1 |
| MIL CARDIAC CATH | 1 |
| GBG 4 W CT ICU | 1 |
| MIL 9 HUDSON | 1 |
| MIL 5 GARDEN NORTH | 1 |
## Warning: There were 2 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq)`.
## ℹ In group 8: `concordance_category = high aPTT low antiXa`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
| concordance_category | classic | low | statistic | p.value | method |
|---|---|---|---|---|---|
| concordant low | 250 | 72 | 98.398 | 0.000 | Chi-squared test for given probabilities |
| low aPTT | 141 | 139 | 0.014 | 0.905 | Chi-squared test for given probabilities |
| concordant | 133 | 173 | 5.229 | 0.022 | Chi-squared test for given probabilities |
| high antiXa | 7 | 47 | 29.630 | 0.000 | Chi-squared test for given probabilities |
| concordant high | 14 | 93 | 58.327 | 0.000 | Chi-squared test for given probabilities |
| high aPTT | 30 | 52 | 5.902 | 0.015 | Chi-squared test for given probabilities |
| low antiXa | 13 | 12 | 0.040 | 0.841 | Chi-squared test for given probabilities |
| high aPTT low antiXa | 1 | 1 | 0.000 | 1.000 | Chi-squared test for given probabilities |
| low aPTT high antiXa | 1 | 1 | 0.000 | 1.000 | Chi-squared test for given probabilities |
## Warning: There were 2 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq)`.
## ℹ In group 4: `concordance = high aPTT low antiXa`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
| concordance | classic | low | statistic | p.value | method |
|---|---|---|---|---|---|
| concordant | 794 | 676 | 9.472 | 0.002 | Chi-squared test for given probabilities |
| discordant aPTT below antiXa | 296 | 372 | 8.647 | 0.003 | Chi-squared test for given probabilities |
| discordant aPTT above antiXa | 86 | 128 | 8.243 | 0.004 | Chi-squared test for given probabilities |
| high aPTT low antiXa | 2 | 2 | 0.000 | 1.000 | Chi-squared test for given probabilities |
| low aPTT high antiXa | 2 | 2 | 0.000 | 1.000 | Chi-squared test for given probabilities |
| n |
|---|
| 115 |
| department_name | n |
|---|---|
| MIL 5 CTICU | 56 |
| MIL 5 CCU | 31 |
| HRT CARDIAC CARE | 23 |
| MIL 4 MICU A | 7 |
| MIL 4 SICU | 1 |
| MIL OPERATING ROOM | 1 |
| MIL CARDIAC CATH | 1 |
| GBG 4 W CT ICU | 1 |
| MIL 9 HUDSON | 1 |
| MIL 5 GARDEN NORTH | 1 |
| department_name | n |
|---|---|
| MIL 5 CTICU | 227 |
| MIL 5 CCU | 202 |
| HRT CARDIAC CARE | 140 |
| MIL 4 MICU A | 11 |
| GBG 4 W CT ICU | 3 |
| MIL 5 GARDEN NORTH | 3 |
| MIL 4 SICU | 1 |
| MIL OPERATING ROOM | 1 |
| MIL CARDIAC CATH | 1 |
| MIL 9 HUDSON | 1 |
| discordance_group | n |
|---|---|
| concordant | 17 |
| discordant aPTT above antiXa | 22 |
| discordant aPTT below antiXa | 57 |
| mixed | 19 |
| name | concordant | discordant aPTT above antiXa | discordant aPTT below antiXa | mixed |
|---|---|---|---|---|
| n | 17.0 | 21.0 | 56.0 | 19.0 |
| median_age | 54.0 | 56.0 | 59.5 | 56.0 |
| iqr_age | 30.0 | 24.0 | 20.2 | 16.5 |
| male_pct | 58.8 | 57.1 | 71.4 | 52.6 |
| median_wt | 76.0 | 83.2 | 87.8 | 88.5 |
| iqr_wt | 21.5 | 26.6 | 29.6 | 29.6 |
| median_ht | 170.0 | 170.0 | 170.7 | 165.1 |
| iqr_ht | 10.1 | 15.8 | 12.8 | 15.2 |
| median_hours | 64.0 | 124.0 | 119.5 | 242.0 |
| iqr_hours | 107.0 | 119.0 | 117.8 | 175.0 |
| discordance_group | n | pct_Cardiac | pct_Pulmonary | pct_ECPR |
|---|---|---|---|---|
| concordant | 10 | 58.8 | 0.0 | 0.0 |
| concordant | 7 | 0.0 | 41.2 | 0.0 |
| discordant aPTT above antiXa | 16 | 76.2 | 0.0 | 0.0 |
| discordant aPTT above antiXa | 2 | 0.0 | 0.0 | 9.5 |
| discordant aPTT above antiXa | 3 | 0.0 | 14.3 | 0.0 |
| discordant aPTT below antiXa | 38 | 67.9 | 0.0 | 0.0 |
| discordant aPTT below antiXa | 3 | 0.0 | 0.0 | 5.4 |
| discordant aPTT below antiXa | 15 | 0.0 | 26.8 | 0.0 |
| mixed | 16 | 84.2 | 0.0 | 0.0 |
| mixed | 1 | 0.0 | 0.0 | 5.3 |
| mixed | 2 | 0.0 | 10.5 | 0.0 |
## Warning: There were 12 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq_complications_once)`.
## ℹ In group 5: `hypothetical_treatment = "classic"` and `complication =
## "hemorrhagic_peripheral_cannulation_site_bleeding"`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 11 remaining warnings.
## # A tibble: 24 × 11
## # Groups: hypothetical_treatment, complication [24]
## complication hypothetical_treatment statistic p.value method data.name
## <chr> <chr> <dbl> <dbl> <chr> <chr>
## 1 death_date classic 2.62 0.455 Chi-s… <NA>
## 2 death_date low 11.8 0.00793 Chi-s… <NA>
## 3 metabolic_hyperbi… classic 0.4 0.819 Chi-s… <NA>
## 4 metabolic_hyperbi… low 0.4 0.819 Chi-s… <NA>
## 5 mechanical_circui… classic 0 1 Chi-s… <NA>
## 6 mechanical_circui… low 0 1 Chi-s… <NA>
## 7 hemorrhagic_perip… classic 0 1 Chi-s… <NA>
## 8 hemorrhagic_perip… low 0 1 Chi-s… <NA>
## 9 neurologic_cns_in… classic NA NA Only … <NA>
## 10 neurologic_cns_in… low NA NA Only … <NA>
## # ℹ 14 more rows
## # ℹ 5 more variables: concordant <int>, `discordant aPTT above antiXa` <int>,
## # `discordant aPTT below antiXa` <int>, mixed <int>,
## # `low aPTT high antiXa` <int>
## Warning: There were 2 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq_complications_once)`.
## ℹ In group 2: `hypothetical_treatment = "classic"` and
## `hemorrhage_thrombosis_death = "hemorrhage_or_thrombosis"`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
| hypothetical_treatment | hemorrhage_thrombosis_death | statistic | p.value | method | concordant | discordant aPTT above antiXa | discordant aPTT below antiXa | mixed |
|---|---|---|---|---|---|---|---|---|
| classic | death | 2.6153846 | 0.4547988 | Chi-squared test for given probabilities | 9 | 4 | 8 | 5 |
| low | death | 11.8461538 | 0.0079292 | Chi-squared test for given probabilities | 5 | 4 | 14 | 3 |
| classic | hemorrhage_or_thrombosis | 1.5714286 | 0.6658854 | Chi-squared test for given probabilities | 3 | 1 | 1 | 2 |
| low | hemorrhage_or_thrombosis | 0.4285714 | 0.9342791 | Chi-squared test for given probabilities | 2 | 2 | 2 | 1 |
## Warning: There were 2 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq_complications_once)`.
## ℹ In group 2: `hypothetical_treatment = "classic"` and
## `hemorrhage_thrombosis_death = "hemorrhage_or_thrombosis"`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
| hypothetical_treatment | hemorrhage_thrombosis_death | statistic | p.value | method | concordant | discordant aPTT above antiXa | discordant aPTT below antiXa | mixed |
|---|---|---|---|---|---|---|---|---|
| classic | death | 2.6153846 | 0.4547988 | Chi-squared test for given probabilities | 9 | 4 | 8 | 5 |
| low | death | 11.8461538 | 0.0079292 | Chi-squared test for given probabilities | 5 | 4 | 14 | 3 |
| classic | hemorrhage_or_thrombosis | 1.5714286 | 0.6658854 | Chi-squared test for given probabilities | 3 | 1 | 1 | 2 |
| low | hemorrhage_or_thrombosis | 0.4285714 | 0.9342791 | Chi-squared test for given probabilities | 2 | 2 | 2 | 1 |
## Warning: There were 2 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `results = map(data, group_chisq_complications_once)`.
## ℹ In group 2: `hypothetical_treatment = "classic"` and
## `hemorrhage_thrombosis_death = "hemorrhage_or_thrombosis"`.
## Caused by warning in `chisq.test()`:
## ! Chi-squared approximation may be incorrect
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
| hypothetical_treatment | hemorrhage_thrombosis_death | statistic | p.value | method | concordant | discordant |
|---|---|---|---|---|---|---|
| classic | death | 2.4615385 | 0.1166645 | Chi-squared test for given probabilities | 9 | 17 |
| low | death | 9.8461538 | 0.0017019 | Chi-squared test for given probabilities | 5 | 21 |
| classic | hemorrhage_or_thrombosis | 0.1428571 | 0.7054570 | Chi-squared test for given probabilities | 3 | 4 |
| low | hemorrhage_or_thrombosis | 1.2857143 | 0.2568393 | Chi-squared test for given probabilities | 2 | 5 |
# Fit mixed-effects model with random intercept for patient (mrn)
discordance_model <- lmer(
heparin_assay_quantitative ~ poly(activated_partial_thromboplastin_time, 2) + (1 | mrn),
data = discordance_data)
# Create prediction grid over the range of predictor
new_data <- data.frame(
activated_partial_thromboplastin_time = seq(
min(discordance_data$activated_partial_thromboplastin_time, na.rm = TRUE),
max(discordance_data$activated_partial_thromboplastin_time, na.rm = TRUE),
length.out = 300 ),
mrn = discordance_data$mrn[1] # Assign any existing patient ID for prediction
)
pred_interval <- merTools::predictInterval(
discordance_model, # model as first argument, no name
newdata = new_data,
level = 0.99,
n.sims = 1000,
which = "fixed",
include.resid.var = TRUE)
# Bind predictions to the new_data
new_data <- bind_cols(new_data, pred_interval)
# Flag unusual data points outside prediction intervals
discordance_data =
discordance_data %>%
rowwise() %>%
mutate(
# Find closest prediction row by activated_partial_thromboplastin_time
pred_row = list(new_data[which.min(abs(activated_partial_thromboplastin_time - new_data$activated_partial_thromboplastin_time)), ]),
predicted = pred_row$fit,
lower = pred_row$lwr,
upper = pred_row$upr,
unusual = heparin_assay_quantitative < lower | heparin_assay_quantitative > upper
) %>%
ungroup()
# Plot predictions with prediction intervals and flagged unusual points
ggplot() +
geom_ribbon(data = new_data,
aes(x = activated_partial_thromboplastin_time, ymin = lwr, ymax = upr),
fill = "blue", alpha = 0.2) +
geom_line(data = new_data,
aes(x = activated_partial_thromboplastin_time, y = fit),
color = "blue") +
geom_point(data = discordance_data,
aes(x = activated_partial_thromboplastin_time, y = heparin_assay_quantitative, color = unusual)) +
scale_color_manual(values = c("black", "red")) +
labs(
color = "Unusual",
title = "Mixed Model Fit with 99% Prediction Interval",
x = "Activated Partial Thromboplastin Time",
y = "Heparin Assay Quantitative"
) +
theme_minimal()
discordance_data
## # A tibble: 1,180 × 17
## mrn patient_name lab_result_time department_name heparin_infusion_dos…¹
## <chr> <chr> <dttm> <fct> <chr>
## 1 1000… AHMED, AMENA 2024-11-03 23:47:00 MIL 5 CCU 5
## 2 1000… AHMED, AMENA 2024-11-03 23:47:00 MIL 5 CCU 5
## 3 1000… AHMED, AMENA 2024-11-04 06:41:00 MIL 5 CCU 5
## 4 1000… AHMED, AMENA 2024-11-04 06:41:00 MIL 5 CCU 5
## 5 1000… AHMED, AMENA 2024-11-04 15:35:00 MIL 5 CCU 5
## 6 1000… AHMED, AMENA 2024-11-04 15:35:00 MIL 5 CCU 5
## 7 1000… AHMED, AMENA 2024-11-04 19:18:00 MIL 5 CCU 5
## 8 1000… AHMED, AMENA 2024-11-04 19:18:00 MIL 5 CCU 5
## 9 1000… AHMED, AMENA 2024-11-05 06:44:00 MIL 5 CCU 5
## 10 1000… AHMED, AMENA 2024-11-05 06:44:00 MIL 5 CCU 5
## # ℹ 1,170 more rows
## # ℹ abbreviated name: ¹heparin_infusion_dose_value_units_kg_hr
## # ℹ 12 more variables: concordance_classic_simple <fct>,
## # concordance_low_simple <fct>, discordance_group <fct>,
## # hypothetical_treatment <chr>, concordance_category <fct>,
## # activated_partial_thromboplastin_time <dbl>,
## # heparin_assay_quantitative <dbl>, pred_row <list>, predicted <dbl>, …
Note that patients can count in multiple renal failure categories. I.e. Patient X is included in renal Cr 1.5 - 3.0 AND Cr > 3.0.
We need thrombotic complications:
We need additional hemorrhagic complications:
RBCs
FFP
platelet
What are the actual ranges of aPTT and anti-Xa among those with completely concordant versus discordant categories? Why are there different death outcomes? Are the demographics different? Disease processes?